package Mapa;
import java.io.*;
import Logica_Moviemientos.Gravedad;
import Logica_Moviemientos.Inteligencia_Artificial;
import Logica_Moviemientos.Inteligencia_Manual;
import Objetos.*;
import TDA_Lista.*;
import Personajes.*; 

public class Mapa_Logico{
	protected SLinkedList<Enemigo> enemigos;
	protected SLinkedList<Objeto> objetos;
	protected SLinkedList<Item> items;
	protected Mario mario;
	protected Gravedad gravedad;
	protected int ancho,alto, posicionX1,posicionX2;
	protected Inteligencia_Artificial inteligencia_a;
	protected Manejo_Colisiones colisiones;
	
	/**Constructor. */
	public Mapa_Logico(){
		iniciarMapa();
	}
	
	//PARA INICIAR LIMITES DEL MAPA
	public void iniciarLimites(){
		ancho = 190 * 32;
		alto = 25 * 32;
		posicionX1 = 0;
		posicionX2 = 1024;
	}
	
	//PARA OBTENER LOS LIMITES Y MODIFICAR LOS LIMITES
	
	public int getPosicionX1(){
		return posicionX1;
	}
	
	public int getPosicionX2(){
		return posicionX2;
	}
	
	public void setPosicionX1(int n){
		posicionX1 = n;
	}
	
	public void setPosicionX2(int n){
		posicionX2 = n;
	}
	
	//PARA INICIAR LOS OBJETOS Y PERSONAJES DEL MAPA
	
	/**Inicia los objetos y personajes del mapa. */
	public void iniciarMapa(){
		objetos = new SLinkedList<Objeto>();
		enemigos = new SLinkedList<Enemigo>();
		items = new SLinkedList<Item>();
		colisiones = new Manejo_Colisiones(this);
		iniciarLimites();
		cargarLogicaNivel();
		iniciarHilos();
	}
	
	//PARA OBTENER LAS DIMENSIONES DEL MAPA
	
	/**Retorna el alto del mapa. */
	public int obtenerAncho(){
		return ancho;
	}
	
	/**Retorna el ancho del mapa. */
	public int obtenerAlto(){
		return alto;
	}
	
	public Manejo_Colisiones getColisiones(){
		return colisiones;
	}
	
	//PARA AGREGAR OBJETOS Y PERSONAJES AL MAPA LOGICO
	
	/**Carga todos los objetos y personajes logicos en el mapa desde un archivo. */
	private void cargarLogicaNivel(){
		InputStream is = getClass().getResourceAsStream("/Niveles/nivel.txt");
		BufferedReader br = new BufferedReader(new InputStreamReader(is));
		Creador_Objetos_Archivo co = new Creador_Objetos_Archivo(br);
		agregarObjetos(co);
		
		InputStream is2 = getClass().getResourceAsStream("/Niveles/nivel.txt");
		BufferedReader br2 = new BufferedReader(new InputStreamReader(is2));
		Creador_Enemigos_Archivo ce = new Creador_Enemigos_Archivo(br2);
		agregarEnemigos(ce);
		
		agregarMario();
	}
	
	/**Metodo auxiliar para asignar las posiciones de los 
	 * objetos y agregarlos al mapa.*/
	private void agregarObjetos( Creador_Objetos_Archivo c ){
		for( int i = 0; i < 25; i++ ){
			for( int j = 0; j < 300; j++ ){
				Objeto e = c.getMatriz().getObjeto(i, j);
				if(e != null){
					e.setPosicion(j*32, i*32);
					objetos.addLast(e);
				}
			}
		}
	}
	
	/**Metodo auxiliar para asignar las posiciones de los 
	 * enemigos y agregarlos al mapa.*/
	private void agregarEnemigos( Creador_Enemigos_Archivo c ){
		for( int i = 0; i < 25; i++ ){
			for( int j = 0; j < 300; j++ ){
				Enemigo e = c.getMatriz().getEnemigo(i, j);
				if(e != null){
					e.setPosicion(j*32, i*32);
					enemigos.addLast(e);
				}
			}
		}
	}
	
	/**Agraga el mario logico en el mapa. */
	private void agregarMario(){
		if(mario == null){
			mario = new Mario(this);
			Thread hiloMario = new Thread(mario);
			hiloMario.start();
			mario.setInteligencia(new Inteligencia_Manual(this));
		}
		mario.setPosicion(32, 17*32);
	}
	
	//PARA LA GRAVEDAD
	
	/**Setea la gravedad en el mapa. */
	public void setGravedad(boolean b){
		gravedad.setGravedad(b);
	}
	
	//PARA INICIAR Y PARAR LOS HILOS DEL MARIO Y DE LA GRAVEDAD
	
	/**Incia los hilos del mario y de la gravedad. */
	public void iniciarHilos(){
		if(gravedad == null){
			gravedad = new Gravedad(this);
			gravedad.start();
		}
		if(inteligencia_a == null){
			inteligencia_a = new Inteligencia_Artificial(this);
			Thread r = new Thread(inteligencia_a);
			r.start();
		}
	}
	
	//PARA OBTENER OBJETOS O PERSONAJES DEL MAPA
	
	/**Retorna el personaje mario. */
	public Mario obtenerMario(){
		return mario;
	}
	
	/**Retorna todos los objetos del mapa. */
	public SLinkedList<Objeto> obtenerObjetos(){
		return objetos;
	}
	
	/**Retorna todos los enemigos del mapa. */
	public SLinkedList<Enemigo> obtenerEnemigos(){
		return enemigos;
	}
	
	/**Retorna todos los enemigos del mapa. */
	public SLinkedList<Item> obtenerItems(){
		return items;
	}
	
	
	//PARA REMOVER OBJETOS, ITEMS O PERSONAJES DEL MAPA
	
	/**Remueve un objeto del mapa logico. */
	public void removerObjeto(Position<Objeto> o){
		try {
			objetos.remove(o);
		} catch (InvalidPositionException e) {
			System.out.println("Mapa :: removerObjeto(o)");
		}
	}
	
	/**Remueve un enemigo del mapa logico. */
	public void removerEnemigo(Position<Enemigo> p){
		try {
			enemigos.remove(p);
		} catch (InvalidPositionException e) {
			System.out.println("Mapa :: removerPersonaje(p)");
		}	
	}
	
	/**Remueve un item del mapa logico. */
	public void removerItem(Position<Item> i){
		try {
			items.remove(i);
		} catch (InvalidPositionException e) {
			System.out.println("Mapa :: removerPersonaje(p)");
		}	
	}
	
}
